
#include "spthread.h"

#ifdef WIN32

int sp_thread_semaphore_init(sp_thread_semaphore_t * semaphore,unsigned int initvalue,unsigned int maxvalue)
{
	*semaphore = CreateSemaphore(NULL,initvalue,maxvalue,NULL);
	return NULL == * semaphore ? GetLastError() : 0;
}

int sp_thread_semaphore_destroy(sp_thread_semaphore_t * semaphore)
{
	int ret = CloseHandle( *semaphore );
	return 0 == ret ? GetLastError() : 0;
}

int sp_thread_semaphore_post(sp_thread_semaphore_t * semaphore)
{
	int ret = ReleaseSemaphore( *semaphore,1,NULL );
	return 0 != ret ? 0 : GetLastError();
}

int sp_thread_semaphore_wait(sp_thread_semaphore_t * semaphore)
{
	int ret = WaitForSingleObject( *semaphore, INFINITE );
	return WAIT_OBJECT_0 == ret ? 0 : GetLastError();
}

int sp_thread_semaphore_timedwait( sp_thread_semaphore_t * semaphore,DWORD dwMilliseconds)
{
	int ret = WaitForSingleObject( *semaphore, dwMilliseconds );
	return WAIT_OBJECT_0 == ret ? 0 : GetLastError();
}

sp_thread_t sp_thread_self()
{
	return GetCurrentThreadId();
}

int sp_thread_create( sp_thread_t * thread, sp_thread_attr_t * attr,
		sp_thread_func_t myfunc, void * args )
{
	// _beginthreadex returns 0 on an error
	HANDLE h = 0;
	unsigned int id = 0;
	if( NULL != attr ) {
		h = (HANDLE)_beginthreadex(NULL, attr->stacksize, myfunc, args, 0, &id);
	} else {
		h = (HANDLE)_beginthreadex( NULL, 0, myfunc, args, 0, &id );
	}
	*thread = id;
	return h > 0 ? 0 : GetLastError();
}
#else

int sp_thread_semaphore_init(sp_thread_semaphore_t * semaphore,unsigned int initvalue,unsigned int maxvalue)
{
	return sem_init(semaphore,0,initvalue);
}

int sp_thread_semaphore_timedwait( sp_thread_semaphore_t * semaphore,DWORD dwMilliseconds)
{
	int ret = 0;
	struct timespec tv;
    clock_gettime(CLOCK_REALTIME, &tv);
	tv.tv_sec += dwMilliseconds/1000;
	tv.tv_nsec += (dwMilliseconds %1000 * 1000000);
	if(tv.tv_nsec >= BILLION)
    {   
        tv.tv_sec += tv.tv_nsec/BILLION;
        tv.tv_nsec %= BILLION;
    }
	ret = sem_timedwait(semaphore,&tv);
	return ret == 0 ? 0 : errno;

}

#endif
